#include "videoopenglwidget.h"
#include <QOpenGLShaderProgram>
#include <QDebug>

VideoOpenGLWidget::VideoOpenGLWidget(QWidget *parent) : QOpenGLWidget(parent),
    xshift(0), yshift(0), wvideo(10), hvideo(10)
{

}

void VideoOpenGLWidget::initializeGL()
{
    initializeOpenGLFunctions();
//    glEnable(GL_DEPTH_TEST);
//    //混合
//    glEnable(GL_BLEND);
//    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    //涂黑
    glClearColor(0, 0, 0, 1);

    QOpenGLShaderProgram program;

    // Compile vertex shader
    if (!program.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shader/vshader.vert"))
        close();

    // Compile fragment shader
    if (!program.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shader/fshader.frag"))
        close();

    // Link shader pipeline
    if (!program.link())
        close();

    // Bind shader pipeline for use
    if (!program.bind())
        close();

    glUseProgram(program.programId());

    // video texture
    float vertices[] = {
        // positions                    // texture coords(上下颠倒)
         1.0f,  1.0f, 0.0f,      1.0f, 0.0f, // top right
         1.0f, -1.0f, 0.0f,      1.0f, 1.0f, // bottom right
        -1.0f, -1.0f, 0.0f,      0.0f, 1.0f, // bottom left
        -1.0f,  1.0f, 0.0f,      0.0f, 0.0f,  // top left
    };
    unsigned int indices[] = {
        // note that we start from 0!
        0, 1, 3,   // first triangle
        1, 2, 3,    // second triangle
    };

    // video
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glGenBuffers(1, &EBO);
    glBindVertexArray(VAO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);

    // 解除绑定
    glBindVertexArray(0);
}

void VideoOpenGLWidget::resizeGL(int w, int h)
{
    if(mImage.isNull())
    {
        xshift = 0;
        yshift = 0;
        wvideo = w;
        hvideo = h;
    }
    else
    {
        int w_img = mImage.width();
        int h_img = mImage.height();
        qreal rw = (qreal)w/(qreal)w_img;
        qreal rh = (qreal)h/(qreal)h_img;

        if(rw >= rh)
        {
            wvideo = w_img*rh;
            hvideo = h;
            xshift = (w - wvideo) / 2;
            yshift = 0;
        }
        else
        {
            wvideo = w;
            hvideo = h_img*rw;
            xshift = 0;
            yshift = (h - hvideo) / 2;
        }
    }
}

void VideoOpenGLWidget::paintGL()
{
    glViewport(xshift, yshift, wvideo, hvideo);

    // video
    glBindVertexArray(VAO);
    glBindTexture(GL_TEXTURE_2D, textureVideo);

    if (!mImage.isNull())
    {
        const unsigned char *data1 = mImage.constBits();
        // 生成一幅纹理，实际上，每帧都生成纹理的开销很大；
        // 合理的做法应该只生成一次，之后的每帧用glSubTexImage2D上传纹理数据;
        // 本例子仅仅作为技术验证和参考，不做进一步的优化
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
                     mImage.width(), mImage.height(), 0,
                     GL_BGR, GL_UNSIGNED_BYTE, data1);

        glGenerateMipmap(GL_TEXTURE_2D);
    }
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
}

void VideoOpenGLWidget::slotGetOneFrame(QImage img)
{
    mQueue.enqueue(img);
}

void VideoOpenGLWidget::slotUpdate()
{
    if(mQueue.isEmpty())    return;
    mImage = mQueue.dequeue();
    update(); //调用update将执行 paintEvent函数

}
